<?php
/**
 * Created by PhpStorm.
 * User: ownfi
 * Date: 2017-03-31
 * Time: 15:56
 */

namespace App\Services\Impl;


use App\Common\Constant\Params;
use App\Events\MasterOffer;
use App\Events\OrderAppointed;
use App\Events\OrderDelivered;
use App\Events\OrderEmployed;
use App\Events\OrderFinished;
use App\Events\OrderOffered;
use App\Models\Master;
use App\Models\MerchantOrderNum;
use App\Models\Order;
use App\Models\OrderComplain;
use App\Models\OrderDetail;
use App\Models\OrderEvaluate;
use App\Models\OrderGoods;
use App\Models\OrderOffer;
use App\Models\OrderReplenish;
use App\Models\OrderStatus;
use App\Services\IMerchantService;
use App\Services\IOrderService;
use App\Services\IStorageService;
use App\Services\IWeixinService;
use Carbon\Carbon;
use DB;
use Illuminate\Support\Collection;
use Log;

class OrderServiceImpl implements IOrderService
{

    private $storageService;
    private $weixinService;
    private $merchantService;

    public function __construct(IStorageService $storageService, IWeixinService $weixinService, IMerchantService $merchantService)
    {
        $this->storageService = $storageService;
        $this->weixinService = $weixinService;
        $this->merchantService = $merchantService;
    }

    public function listOffering(array $areaIds)
    {
        $orderIds = OrderStatus::whereIn("merchant_status",[Params::ORDER_MERCHANT_STATUS_WAITING,Params::ORDER_MERCHANT_STATUS_OFFERING,Params::ORDER_MERCHANT_STATUS_APPOINTING])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }

        /**
         * 过滤掉师傅本人已报价的订单
         */
        $offeringOrderIds = OrderOffer::where("master_id",getCurrentUserid())->whereIn("status",[Params::OFFER_STATUS_WAITING,Params::OFFER_STATUS_APPOINTING])->get()->pluck('order_id');
        $orderIds = $orderIds->diff($offeringOrderIds);

        /**
         * 匹配地区过滤
         */
        $orderIds = OrderDetail::whereIn("order_id",$orderIds)
            ->whereIn("customer_area_id",$areaIds)->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }
        $master = getCurrentUser();
        return Order::whereIn("id",$orderIds)
            //到报价截止时间之前
            ->where(DB::raw('push_time+'.(config('common.order_offering_endtime')*86400)), '>', time())
            //只匹配师傅服务类型能支持的商家服务类型
//            ->whereIn('service_type',$this->merchantService->transformMasterServiceType($master->service_type))
            ->with('detail')->orderBy('add_time','DESC')->get();
    }

    public function listMatchingOffering($master_id)
    {
        $master = Master::find($master_id);
        if ($master){
            return $this->listOffering($master->service_area_ids);
        }
        return [];
    }

    public function countOffering(array $areaIds)
    {
        $orderIds = OrderStatus::whereIn("merchant_status",[Params::ORDER_MERCHANT_STATUS_WAITING,Params::ORDER_MERCHANT_STATUS_OFFERING,Params::ORDER_MERCHANT_STATUS_APPOINTING])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return 0;
        }

        /**
         * 过滤掉师傅本人已报价的订单
         */
        $offeringOrderIds = OrderOffer::where("master_id",getCurrentUserid())->whereIn("status",[Params::OFFER_STATUS_WAITING,Params::OFFER_STATUS_APPOINTING])->get()->pluck('order_id');
        $orderIds = $orderIds->diff($offeringOrderIds);

        /**
         * 匹配地区过滤
         */
        $orderIds = OrderDetail::whereIn("order_id",$orderIds)
            ->whereIn("customer_area_id",$areaIds)->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return 0;
        }
        $master = getCurrentUser();
        return Order::whereIn("id",$orderIds)
            //到报价截止时间之前
            ->where(DB::raw('push_time+'.(config('common.order_offering_endtime')*86400)), '>', time())
            //只匹配师傅服务类型能支持的商家服务类型
//            ->whereIn('service_type',$this->merchantService->transformMasterServiceType($master->service_type))
            ->count();
    }

    public function countMatchingOffering($master_id)
    {
        $master = Master::find($master_id);
        if ($master){
            return $this->countOffering($master->service_area_ids);
        }
        return 0;
    }

    public function getOrderAllInfoById($orderId)
    {
        return Order::with(['detail','status','goods','merchant','master','myOffer','evaluate'])->find($orderId);
    }

    public function getOrderDetailById($orderId)
    {
        return Order::with(['detail'])->find($orderId);
    }

    public function getOrderById($orderId)
    {
        return Order::find($orderId);
    }

    public function getOffer($orderId, $masterId)
    {
        return OrderOffer::where([
            'order_id'=>$orderId,
            'master_id'=>$masterId,
        ])->first();
    }

    public function loadOrderAllInfo(Order $order)
    {
        $order->load(['detail','status','goods','merchant','master','myOffer','evaluate','replenishs']);
    }

    public function loadOrderDetail(Order $order)
    {
        $order->load(['detail']);
    }

    public function loadOrderRefund(Order $order)
    {
        $order->load(['status','refunds']);
    }

    public function listMasterOffered($masterId,&$page = 1)
    {
        $orderIds = OrderOffer::where("master_id",$masterId)->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            $page = 0;
            return Collection::make([]);
        }
        $orders =  Order::whereIn("id",$orderIds)->where("add_time",'>=',Carbon::now()->subDays(config('common.list_offered_days'))->timestamp)->with('detail','myOffer','goods','status')->orderBy('add_time','DESC')
            ->offset(($page-1) * config('common.perpage'))->limit(config('common.perpage'))->get();
        if ($orders->isEmpty() || ($orders->count() < config('common.perpage'))){
            $page = 0;
        }
        return $orders;
    }

    public function countServing($masterId)
    {
        $orderIds = OrderOffer::where(["master_id"=>$masterId,"status"=>Params::OFFER_STATUS_EMPLOYED])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return 0;
        }
        return OrderStatus::whereIn("order_id",$orderIds)
            ->whereIn("merchant_status",[Params::ORDER_MERCHANT_STATUS_PAID,Params::ORDER_MERCHANT_STATUS_SERVING])
            ->whereIn("master_status",[Params::ORDER_MASTER_STATUS_WAITING,Params::ORDER_MASTER_STATUS_SERVING,Params::ORDER_MASTER_STATUS_APPOINTED,Params::ORDER_MASTER_STATUS_LOGISTICS_OK,Params::ORDER_MASTER_STATUS_LOGISTICS_FAILED])
            ->count();
    }

    public function countFinished($masterId)
    {
        $orderIds = OrderOffer::where(["master_id"=>$masterId,"status"=>Params::OFFER_STATUS_EMPLOYED])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return 0;
        }
        return OrderStatus::whereIn("order_id",$orderIds)
            ->whereIn("merchant_status",[Params::ORDER_MERCHANT_STATUS_FINISHED])
            ->whereIn("master_status",[Params::ORDER_MASTER_STATUS_FINISHED])
            ->count();
    }

    public function countAll($masterId)
    {
        $orderIds = OrderOffer::where(["master_id"=>$masterId,"status"=>Params::OFFER_STATUS_EMPLOYED])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return 0;
        }
        return Order::whereIn("id",$orderIds)
            ->count();
    }

    public function listMasterServing($masterId,$page = 1)
    {
        $orderIds = OrderOffer::where(["master_id"=>$masterId,"status"=>Params::OFFER_STATUS_EMPLOYED])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }
        $orderIds = OrderStatus::whereIn("order_id",$orderIds)
            ->whereIn("merchant_status",[Params::ORDER_MERCHANT_STATUS_PAID,Params::ORDER_MERCHANT_STATUS_SERVING])
            ->whereIn("master_status",[Params::ORDER_MASTER_STATUS_WAITING,Params::ORDER_MASTER_STATUS_SERVING,Params::ORDER_MASTER_STATUS_APPOINTED,Params::ORDER_MASTER_STATUS_LOGISTICS_OK,Params::ORDER_MASTER_STATUS_LOGISTICS_FAILED])
            ->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }
        return Order::whereIn("id",$orderIds)->with('detail','status','myOffer','goods')->orderBy('pay_time','DESC')->get();
    }

    public function listMasterFinished($masterId,$page = 1)
    {
        $orderIds = OrderOffer::where(["master_id"=>$masterId,"status"=>Params::OFFER_STATUS_EMPLOYED])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }
        $orderIds = OrderStatus::whereIn("order_id",$orderIds)
            ->whereIn("merchant_status",[Params::ORDER_MERCHANT_STATUS_FINISHED])
            ->whereIn("master_status",[Params::ORDER_MASTER_STATUS_FINISHED])
            ->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }
        return Order::whereIn("id",$orderIds)->with('detail','status','myOffer','goods')->orderBy('upd_time','DESC')->get();
    }

    public function listMasterAll($masterId,&$page = 1)
    {
        $orderIds = OrderOffer::where(["master_id"=>$masterId,"status"=>Params::OFFER_STATUS_EMPLOYED])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            $page = 0;
            return Collection::make([]);
        }
        $orders = Order::whereIn("id",$orderIds)->with('detail','status','myOffer','goods','refunds')->orderBy('upd_time','DESC')
            ->offset(($page-1) * config('common.perpage'))->limit(config('common.perpage'))->get();
        if ($orders->isEmpty() || ($orders->count() < config('common.perpage'))){
            $page = 0;
        }
        return $orders;
    }

    public function giveOffer($order_id, $master_id, $price, $message = null)
    {
        $offer_count = OrderOffer::where('order_id',$order_id)->count();
        // chenqinglin检查是否已经有师傅被雇佣，有一些师傅在微信时间很长，造成订单在后台已经被雇佣师傅
        $is_employed = false;
        $offer_all = OrderOffer::where('order_id',$order_id)->select('status')->get();
        $offer_all->each(function($item) use (&$is_employed) {
            if($item->status == 2) {
                $is_employed = true;
            }
        });
        $status = $is_employed ? 3:0;
        // chenqinglin end
        $offer = OrderOffer::firstOrCreate([
                'order_id'=>$order_id,
                'master_id'=>$master_id,

            ],[
                'price'=>$price,
                'message'=>$message,
                'status'=>$status,
            ]);

        if (!$offer){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'offer create fail'));
            return false;
        }
        // chenqinglin order 有时候师傅已经被雇用，此时再有师傅报价就不要再从写数据库状态了。
         $os_ret = OrderStatus::where('order_id',$order_id)->first();
         
         if($os_ret['merchant_status'] > Params::ORDER_MERCHANT_STATUS_OFFERING) {
             Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'order status is next part do not set status '));
         } else {
             $ret = OrderStatus::where('order_id',$order_id)->take(1)->update(['merchant_status'=>Params::ORDER_MERCHANT_STATUS_OFFERING]);
         }
       
        if (!$ret){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'order status update fail'));
            return false;
        }

        if ($offer_count == 0){
            $ret = event(new OrderOffered($order_id));
        }

        return $ret;

    }

    public function appoint($order_id, $door_time)
    {
        $ret = OrderStatus::where('order_id',$order_id)->take(1)->update([
            'merchant_status'=>Params::ORDER_MERCHANT_STATUS_SERVING,
            'master_status'=>Params::ORDER_MASTER_STATUS_APPOINTED,
            'appoint_time'=>time(),
            'door_time'=>$door_time
        ]);

        event(new OrderAppointed($order_id));
        return $ret;
    }

    public function delivery($order_id, $delivery_status, array $deliver_imgs_mediaId, $deliver_except = null)
    {
        if (!in_array($delivery_status,[Params::ORDER_MASTER_STATUS_LOGISTICS_OK,Params::ORDER_MASTER_STATUS_LOGISTICS_FAILED])){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'wrong param: $delivery_status'));
            return false;
        }

        /**
         * 过滤空的
         */
        $deliver_imgs_mediaId = array_filter($deliver_imgs_mediaId);
        /**
         * 从微信服务器下载图片
         */
        $deliver_imgs_stream = $this->weixinService->getMedia($deliver_imgs_mediaId);

        /**
         * 上传图片到云
         */
        $deliver_imgs = [];
        foreach ($deliver_imgs_stream as $deliver_img_stream){
            $deliver_imgs[] = $this->storageService->saveStream($deliver_img_stream);
        }
        $deliver_imgs = array_filter($deliver_imgs);
        if (empty($deliver_imgs)){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'empty images'));
            return false;
        }

        $ret = OrderStatus::where('order_id',$order_id)->take(1)->update([
            'master_status'=>$delivery_status,
            'deliver_time'=>time(),
            'deliver_imgs'=>json_encode($deliver_imgs),
            'deliver_except'=>$deliver_except
        ]);
        if (!$ret){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'status update fail'));
            return false;
        }

        $ret = $ret && event(new OrderDelivered($order_id));

        return $ret;

    }

    public function verifyConfirmCode($order_id, $confirm_code)
    {
        return Order::find($order_id)->confirm_code == $confirm_code;
    }

    public function applyFinish($order_id, array $finish_imgs, $finish_ticket_img, $tmall_check_img = null, $finish_message = null)
    {
        /**
         * 过滤空的
         */
        $finish_imgs = array_filter($finish_imgs);
        /**
         * 从微信服务器下载图片
         */
        $media_ids = array_merge([$finish_ticket_img],[$tmall_check_img],$finish_imgs);
        $media_streams = $this->weixinService->getMedia($media_ids);
        $finish_ticket_img_stream = array_shift($media_streams);
        $tmall_check_img_stream = array_shift($media_streams);
        $finish_imgs_stream = $media_streams;

        /**
         * 上传图片到云
         */
        $finish_ticket_img = $this->storageService->saveStream($finish_ticket_img_stream);
        $tmall_check_img = $tmall_check_img_stream ? $this->storageService->saveStream($tmall_check_img_stream) : null;
        $finish_imgs = [];
        foreach ($finish_imgs_stream as $finish_img_stream){
            $finish_imgs[] = $this->storageService->saveStream($finish_img_stream);
        }
        $finish_imgs = array_filter($finish_imgs);
        if (empty($finish_imgs)){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'empty images'));
            return false;
        }

        $ret = OrderStatus::where('order_id',$order_id)->take(1)->update([
            'merchant_status'=>Params::ORDER_MERCHANT_STATUS_FINISHED,
            'master_status'=>Params::ORDER_MASTER_STATUS_FINISHED,
            'finish_time'=>time(),
            'finish_imgs'=>json_encode($finish_imgs),
            'finish_ticket_img'=>$finish_ticket_img,
            'tmall_check_img'=>$tmall_check_img,
            'finish_message'=>$finish_message
        ]);
        if (!$ret){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'status update fail'));
            return false;
        }

        $ret = $ret && event(new OrderFinished($order_id));

        return $ret;
    }

    public function mark($order_id, $master_id, $mark)
    {
        return OrderOffer::where(['order_id'=>$order_id,'master_id'=>$master_id])->take(1)->update(['mark'=>$mark]);
    }

    public function listEvaluateWaiting($master_id)
    {
        $orderIds = OrderOffer::where(["master_id"=>$master_id,"status"=>Params::OFFER_STATUS_EMPLOYED])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }
        return OrderEvaluate::whereIn("oe_orderid",$orderIds)
            ->where("oe_response",'')
            ->orWhereNull("oe_response")
            ->with('order','merchant')
            ->get();
    }

    public function listEvaluateAll($master_id)
    {
        $orderIds = OrderOffer::where(["master_id"=>$master_id,"status"=>Params::OFFER_STATUS_EMPLOYED])->select('order_id')->get()->pluck('order_id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }
        return OrderEvaluate::whereIn("oe_orderid",$orderIds)
            ->with('order','merchant')
            ->get();
    }

    public function reply($order_id, $reply)
    {
        return OrderEvaluate::where('oe_orderid',$order_id)->take(1)->update([
            'oe_response'=>$reply,
        ]);
    }

    public function checkConfirmCode($order_id, $confirm_code)
    {
        if (!$order = Order::find($order_id)){
            Log::error(sprintf('%s/%s::%s[%d] %s',__NAMESPACE__,__CLASS__,__FUNCTION__,__LINE__-2,'miss order'));
            return false;
        }
        return $order->confirm_code == $confirm_code;
    }

    public function getComplainCount($master_id)
    {
        $orderIds = Order::where("master_id",$master_id)->select('id')->get()->pluck('id');
        if ($orderIds->isEmpty()){
            return [0,0];
        }
        $waiting_complain_count = OrderComplain::where('oc_handle_status',Params::COMPLAIN_STATUS_WAITING)->whereIn("oc_orderid",$orderIds)->count();
        $handled_complain_count = OrderComplain::whereIn('oc_handle_status',[Params::COMPLAIN_STATUS_OK,Params::COMPLAIN_STATUS_CANCEL])->whereIn("oc_orderid",$orderIds)->count();

        return [$waiting_complain_count,$handled_complain_count];
    }

    public function getComplainWaitingList($master_id)
    {
        $orderIds = Order::where("master_id",$master_id)->select('id')->get()->pluck('id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }
        return OrderComplain::where('oc_handle_status',Params::COMPLAIN_STATUS_WAITING)->whereIn("oc_orderid",$orderIds)->orderBy('oc_add_time','DESC')->get();
    }

    public function getComplainHandledList($master_id)
    {
        $orderIds = Order::where("master_id",$master_id)->select('id')->get()->pluck('id');
        if ($orderIds->isEmpty()){
            return Collection::make([]);
        }
        return OrderComplain::whereIn('oc_handle_status',[Params::COMPLAIN_STATUS_OK,Params::COMPLAIN_STATUS_CANCEL])->whereIn("oc_orderid",$orderIds)->orderBy('oc_add_time','DESC')->get();
    }

    public function replenishList($order_id)
    {
        return OrderReplenish::where('order_id',$order_id)->whereNotEmpty('pay_time')->orderBy('pay_time','ASC')->get();
    }


}